feat: node-gtk flatpak — package apps as installable Flatpaks#490
Merged
Conversation
The format real users install: one-click via GNOME Software, Flathub-
ready, sandboxed, with the GTK runtime shared across apps (the smoke
app's deliverable is an 18MB .flatpak vs its 100MB portable tar.gz).
GTK comes from org.gnome.Platform — nothing GTK-related is bundled.
flatpak-builder builds offline; instead of the usual lockfile→sources
generators, the same app-tree step `node-gtk bundle` uses stages the
app + production node_modules as a plain dir source (new rebuildAddon
mode: node-gtk ships its compile inputs — src/, binding.gyp, nan — and
no host binding). The addon is compiled in-sandbox against the
runtime's GTK with npm's internal node-gyp: --nodedir points at the
node SDK extension's bundled headers (offline), and module_name/
module_path are passed explicitly since binding.gyp is node-pre-gyp
style. The node binary is copied from the SDK extension into /app/bin.
Generates manifest + launcher + .desktop + AppStream metainfo + icon
install from the shared "bundle" config (new: summary, icon, license,
categories, flatpak.{runtimeVersion,node,finishArgs}), builds with
flatpak-builder or org.flatpak.Builder (granting the output dir to its
sandbox — it cannot see /tmp), and emits a single-file .flatpak via
build-bundle --runtime-repo so end-user installs fetch the Platform
from Flathub automatically.
Verified end-to-end locally: built, installed and ran the smoke app
under GNOME Platform 49 / node26 extension. CI checks generation only
(the sandbox build needs the ~1GB GNOME SDK).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Apps written with the `gi:` import scheme (the `node-gtk create` default) crashed at startup in bundles and flatpaks with ERR_UNSUPPORTED_ESM_URL_SCHEME: the loader hooks are installed by `node --import node-gtk/register`, which the generated launchers only passed when the app configured nodeArgs by hand. Launchers now pass --import node-gtk/register by default; the new `register: false` config key opts out. Harmless for CJS apps — register.mjs only installs module hooks. Verified: an ESM `import Gtk from 'gi:Gtk-4.0'` app built, installed and ran as a flatpak; the CJS bundle smoke test still passes with the flag present. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A rolling-release host can expose introspected names an older GNOME runtime doesn't (glib 2.88 introspects g_unix_signal_add_full as GLibUnix.signalAdd; the GNOME 49 runtime's glib 2.86 exposes signalAddFull). Document the version-tolerant lookup pattern and the one-liner to get a node REPL inside the sandbox. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner
Author
|
Consolidated into #489 per review preference — that PR now carries the full bundle+flatpak work. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Stacked on #489 (base:
bundle-cli) — merge that first, then rebase this onto master.The installable deliverable for real users:
MyApp.flatpakis a single file users double-click to install through GNOME Software on any distro — it embeds the Flathub repo reference so the GNOME runtime is fetched automatically. The generated manifest is what a Flathub submission needs (docs cover the path +flatpak-builder-lint).Verified end-to-end locally: built, installed, and ran a GTK4 smoke app under GNOME Platform 49 with the node26 SDK extension. The deliverable is 18 MB vs the same app's 100 MB portable tar.gz — GTK is shared via
org.gnome.Platform, exactly the traction story.How
flatpak-builderbuilds without network, which normally forces lockfile→sources generators (weak for pnpm). Instead, the app-tree step from feat: ship node-gtk apps —bundle(portable) +flatpak(installable) #489 stages the app + production node_modules as a plaindirsource. NewrebuildAddonmode: node-gtk ships its compile inputs (src/,binding.gyp,nan) instead of a host-built binding.--nodedir=/usr/lib/sdk/node<N>(the SDK extension bundles node headers — still offline) and explicit-Dmodule_name/-Dmodule_path(binding.gyp is node-pre-gyp style; itsaction_after_buildthen installs the binding wherelib/native.jslooks).org.freedesktop.Sdk.Extension.node<N>into/app/bin(the Platform doesn't ship node)..desktop, AppStream metainfo (with explicit TODOs for Flathub review), icon install — all from the shared"bundle"config. New fields:summary,icon,license,categories,flatpak.{runtimeVersion,node,finishArgs}.finishArgs.flatpak-builderororg.flatpak.Builder(the flatpak-run variant gets--filesystem=<out>— its sandbox can't see /tmp).Docs
doc/bundling.mdrestructured: Flatpak first (installable, Flathub path, sandbox permissions, the "flatpak id must equal your GApplication id" gotcha), portable bundles second, roadmap (win/mac/AppImage) unchanged.Testing
scripts/flatpak-smoke-test.jsin CI (ubuntu, node 24): generation-only — asserts manifest/desktop/metainfo/launcher correctness and that the staged sources are compilable (binding.gyp+src/+nanpresent, no host binding leaked). The full sandbox build isn't run per-CI-run (downloads the ~1 GB GNOME SDK).bundlesmoke test still passes after the shared-config refactor.Follow-ups
bundleplatform modules (unchanged roadmap)🤖 Generated with Claude Code